package coalition.formation.coalitions;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import coalition.formation.combinations.IndexedCombination;
import coalition.formation.combinations.SuperSet;
import coalition.formation.externality.Externality;
import coalition.formation.partitions.Partition;
import coalition.formation.partitions.PartitionDecorator;
import coalition.formation.utils.Util;




public class SplitProof {

	Externality externality;
	int numElements;

	public SplitProof(Externality externality){
		this.externality = externality;
		this.numElements = externality.getSize();
	}
	
	public List<int[]> getSplitProofPartitions(){
		Partition testPartition = new Partition(numElements);
		ArrayList<int[]> partitions = testPartition.getPartitions();
		return getSplitProofPartitions(partitions);
	}
	
	public List<int[]> getSplitProofPartitions(List<int[]> partitions){
		List<int[]> result = new ArrayList<int[]>();
			
		for(int[] partition : partitions){
			System.out.println("starting partition:" + coalition.formation.utils.Util.printIntArray(partition));
			float[] thisExternalities = externality.getExternalities(partition);
			System.out.println("\texternalities:" + coalition.formation.utils.Util.printFloatArray(thisExternalities)+ "\n");
			boolean isCore = true;
			//check every coalition
			int counter = -1;
			for(int[] coalition: PartitionDecorator.getCoalitionLists(partition)){
				//check every subset of this coalition for split-proofness
				
				counter++;
				System.out.println("\tDefecting from coalition: " + counter);
				for(int[] subset: IndexedCombination.findCombinations(coalition.length, coalition)){
			
					int[] otherPartition = splitAgents(partition, subset);
					int[] subsetIndicatorArray = Core.getCoalitionIndicatorArray(subset, partition.length);
					System.out.println("\t\tsplit indicator:" + Util.printIntArray(subsetIndicatorArray));
					System.out.println("\t\tsplit list:" + Util.printIntArray(subset));
					System.out.println("\t\tresulting partition:" + Util.printIntArray(otherPartition) );					
					
					float[] otherExternalities = externality.getExternalities(otherPartition);
					
					boolean isGreaterThan = Core.floatArrayGreaterThan(otherExternalities, thisExternalities, subset);
					String cmpSymbol = isGreaterThan ? " > " : " !> ";
					System.out.println("\t\tresulting externalities:" + 
							Util.printFloatArray(otherExternalities, subsetIndicatorArray) + 
							cmpSymbol + 
							Util.printFloatArray(thisExternalities, subsetIndicatorArray)+ 
							"\n");					
					
					if(isGreaterThan){
						isCore = false; 
						System.out.println("\t\tviolates split-proof-ness");
						//break;
					}
				
				}
			}		
			if(isCore)
				result.add(partition);					
		}
		
		return result;
	}
	
	static int[] splitAgents(int[] partition, int[] agents){
		int[] newPartition = Arrays.copyOf(partition, partition.length);
		for(int i: agents){
			//use an index one greater than anything present in
			//a normalized partition; this new index will reprsent
			//the splitting group
			newPartition[i] = partition.length;
		}	
		int[] normalizedPartition = PartitionDecorator.reduceIndices(newPartition);
		return normalizedPartition;
	}
	
}
